#include <vector>

//#define CASE1
//#define CASE2
//#define CASE3
#define CASE4

#ifdef CASE1
#include "Triangle.h"
#include "Rectangle.h"
#endif // CASE1

#ifdef CASE2
#include "TextParser.h"
#endif // CASE2

#ifdef CASE3
#include "XmlParser.h"
#endif // CASE3

#ifdef CASE4
#include <iostream>
#include "Triangle.h"
#include "Rectangle.h"
#include "squirrel.h"
#include "sqrat.h"
#include "SFML/System/Clock.hpp"
#endif // CASE4

using std::pair;
using std::vector;
using sffs::Drawable;
using sf::Color;

#ifdef CASE1
using sffs::Rectangle;
using sffs::Triangle;
#endif

#ifdef CASE4
using sffs::Rectangle;
using sffs::Triangle;
#endif

int main(int argc, char** argv)
{

	// ===========================================================
	// Initialisation :

	// Create a window with an OpenGL context
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "SFFS");
	// Specify in wich windows we will drow the shapes
	sffs::Drawable::Init(window);

	#ifdef CASE1
	Triangle * t1 = new Triangle(pair<float, float>(100.68f, 100.26f), pair<float, float>(50, 50), pair<float, float>(200, 150), Color(255, 0, 0)) ;
	#endif // CASE1

	#ifdef CASE2
	// Load the file used to generate shape
	TextParser parser("bin/Scene.txt") ;
	const vector<Drawable*> toRender = parser.GetDrawable() ;
	#endif // CASE2

	#ifdef CASE3
	// Load the xml used to generate shape
	XmlParser parser("bin/Scene.xml") ;
	const vector<Drawable*> toRender = parser.GetDrawable() ;
	sf::Clock* timer = new sf::Clock() ;
	timer->Reset() ;
	#endif

	#ifdef CASE4
	Sqrat::DefaultVM::Set(sq_open(1024)) ;

	// We bind the class "Triangle" :
	Sqrat::Class<sffs::Triangle> triangle ;
	triangle
		// Member Functions
		.Func(	_SC("SetCorner0"),	&sffs::Triangle::SetCorner0)
		.Func(	_SC("SetCorner1"),	&sffs::Triangle::SetCorner1)
		.Func(	_SC("SetCorner2"),	&sffs::Triangle::SetCorner2)
		.Func(	_SC("SetColor"),	&sffs::Triangle::SetColor)
		.Func(	_SC("Draw"),		&sffs::Triangle::Draw) ;
	Sqrat::RootTable().Bind(_SC("Triangle"), triangle) ;

	// We bind the class "Rectangle" :
	Sqrat::Class<sffs::Rectangle> rectangle ;
	rectangle
		// Member Functions
		.Func(	_SC("SetWH"),		&sffs::Rectangle::SetWidthHeight)
		.Func(	_SC("SetCenter"),	&sffs::Rectangle::SetCenter)
		.Func(	_SC("SetColor"),	&sffs::Rectangle::SetColor)
		.Func(	_SC("Draw"),		&sffs::Rectangle::Draw) ;
	Sqrat::RootTable().Bind(_SC("Rectangle"), rectangle) ;

	// Run the file containing squirrel
	Sqrat::Script script ;
	try
	{
		script.CompileFile("bin/Scene.nut") ;
	}
	catch(Sqrat::Exception ex)
	{
		std::cout << _SC("Compile Failed: ") << ex.Message() << std::endl ;
		exit(-3) ;
	}
	
	try
	{
		script.Run() ;
	}
	catch(Sqrat::Exception ex)
	{
		std::cout << _SC("Run Failed: ") << ex.Message() << std::endl ;
		exit(-3) ;
	}

	// Get back the function called for each draw
	Sqrat::Function onDraw(Sqrat::RootTable(), _SC("OnDraw")) ;
	sf::Clock* timer = new sf::Clock() ;
	timer->Reset() ;
	#endif // CASE4

	// ===========================================================
	// Runing :

	bool running = true;
	while(running) 
	{
		sf::Event event;
		while(window.GetEvent(event)) 
		{
			// Window closed
			if(event.Type == sf::Event::Closed) {
				running = false;
				window.Close();
			}
			 // Escape key pressed
			if((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Escape)) {
				running = false;
				window.Close();
			}
		}

		// We clean the windows to draw our scene
		window.Clear(Color(255,255,255));

		// Draw scene :

		#ifdef CASE1
		// Case 1 : Hard code :
		t1->Draw() ;
		#endif //CASE1

		#ifdef CASE2
		// Case 2 : Reading from a text file
		for(vector<Drawable*>::const_iterator it = toRender.begin() ; it != toRender.end() ; it++)
		{
			(*it)->Draw() ;
		}
		#endif // CASE2

		#ifdef CASE3
		// Case 3 : Reading from an xml file
		for(vector<Drawable*>::const_iterator it = toRender.begin() ; it != toRender.end() ; it++)
		{
			(*it)->Draw() ;
			//TODO Q4 : timer et changement de couleur
			(*it)->ChangeColor(static_cast<int>(timer->GetElapsedTime()*1000));
		}
		#endif // CASE3

		#ifdef CASE4
		onDraw.Evaluate<int>(static_cast<int>(timer->GetElapsedTime()*1000)) ;
		#endif // CASE4

		// Display
		window.Display();
	}
	// ===========================================================

	#ifdef CASE4
	delete timer ;
	#endif // CASE4

	return EXIT_SUCCESS;
}
